#pragma once 
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <unordered_map>
#include <cassert>

#include "../comm/util.hpp"
#include "../comm/log.hpp"

namespace ns_model
{
    using namespace ns_util;
    using namespace ns_log;

    struct Question
    {
        std::string _number; // 题目编号 唯一
        std::string _title;  // 题目名称
        std::string _star;   // 题目难度等级
        int _cpu_limit;      // 时间要求
        int _mem_limit;      // 空间要求
        std::string _desc;   // 题目细节
        std::string _header; // 编辑框预设代码
        std::string _tail;   // 题目测试用例，和header进行拼接
    };

    const std::string qusetions_list_path = "./questions/questions.list";
    const std::string questins_path  = "./questions/";

    class Model
    {
    public:
        Model()
        {
            assert(LoadQuestionList(qusetions_list_path));
        }
        ~Model()
        {}

        bool GetAllQuestions(std::vector<struct Question> *out)
        {
            if(_questions.size() == 0)
            {
                LOG(Loglevel::FATAL) << "用户获取题库失败\n";
                return false;
            }
            for(auto& question : _questions)
            {
                out->push_back(question.second);
            }
            return true;
        }

        bool GetOneQuestion(const std::string &number, struct Question *out)
        {
            if(_questions.size() == 0)
            {
                LOG(Loglevel::FATAL) << "用户获取指定题目失败: " << number << "\n";
                return false;
            }
            const auto& iter = _questions.find(number);
            if(iter == _questions.end())
                return false;
            else
            {
                *out = iter->second;
                return true;
            }
        }
    private:
        bool LoadQuestionList(const std::string &questions_list)
        {
            std::ifstream ifs(questions_list);
            if(!ifs.is_open()) 
            {
                LOG(Loglevel::FATAL) << "加载题库失败, 请检查题库是否存在\n";
                return false;
            }

            std::string line;
            while(std::getline(ifs, line))
            {
                std::vector<std::string> tokens;
                StringUtil::SplitString(line, &tokens, " ");
                if(tokens.size() != 5)
                {
                    LOG(Loglevel::WARN) << "加载部分题库失败, 请检查文件格式\n";
                    continue;
                }

                struct Question q;
                q._number = tokens[0];
                q._title = tokens[1];
                q._star = tokens[2];
                q._cpu_limit = atoi(tokens[3].c_str());
                q._mem_limit = atoi(tokens[4].c_str());
                
                std::string path = questins_path;
                path += q._number;
                path += "/";

                FileUtil::ReadFile(path + "desc.txt", &q._desc, true);
                FileUtil::ReadFile(path + "header.cpp", &q._header, true);
                FileUtil::ReadFile(path + "tail.cpp", &q._tail, true);
                _questions.insert({q._number, q});
            }

            ifs.close();
            LOG(Loglevel::INFO) << "加载题库完毕...\n";
            return true;
        }
    private:
        std::unordered_map<std::string, struct Question> _questions;
    };
}